﻿using System.Collections;
using Fuse8.ContentManagementFramework.Administration.Models;
using Fuse8.ContentManagementFramework.Administration.Models.MetaFields;
using Fuse8.ContentManagementFramework.BizFacade.Services;
using Fuse8.ContentManagementFramework.Domain;
using Fuse8.ContentManagementFramework.Domain.Special;
using Fuse8.ContentManagementFramework.SystemFacade;
using Fuse8.ContentManagementFramework.SystemFacade.Extensions;
using Fuse8.ContentManagementFramework.SystemFacade.Utilities;
using Fuse8.DomainFramework.BusinessService;
using Fuse8.DomainFramework.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web.Mvc;
using Telerik.Web.Mvc;

namespace Fuse8.ContentManagementFramework.Administration.Controllers
{
    public class CmsMetaFieldController : CmsAdminController
    {
        private IEntityBusinessService<CmsEntityMetaField, int> _entityMetaFieldService = new BusinessServiceFacade<CmsEntityMetaField, int>();

        private readonly Dictionary<string, string> editActions = new Dictionary<string, string>()
                                                             {
                                                                 {CmsConstants.SiteTypeParameter, "/admin/cmssitemetafields/edit"},
                                                                 {CmsConstants.PageTypeParameter, "/admin/cmspagemetafields/edit"},
                                                                 {CmsConstants.UserTypeParameter, "/admin/cmsusermetafield/edit"},
                                                                 {CmsConstants.ContentParameter + "(\\d+)", "/admin/cmscontenttype/editmeta/{0}"}
                                                             };

        private static readonly Dictionary<string, string> typeEditorMappings = new Dictionary<string, string>()
                                                                         {
                                                                             {TypeInterpreter.GetTypeName(typeof(bool)), "Checkbox"},
                                                                             {TypeInterpreter.GetTypeName(typeof(CmsPagePropertiesContainer)), "CmsPagePropertiesContainer"}
                                                                         };

        public ActionResult Index(int? pageSize)
        {
            var data = _entityMetaFieldService.FindAll();

            ViewBag.PageSize = pageSize ?? DefaultPageSize;

            return View(data);
        }

        [GridAction]
        public ActionResult _Index(int? pageSize)
        {
            var data = _entityMetaFieldService.FindAll();

            ViewBag.PageSize = pageSize ?? DefaultPageSize;

            return View(
                   new GridModel<CmsEntityMetaField>
                   {
                       Data = data
                   });
        }

        public ActionResult EntityMetaFields(string entityTypeParameter)
        {
            var data = new CmsEntityMetaFieldLinkService().FindForEntityType(entityTypeParameter);
            return PartialView("MetaFields/EntityMetaFields", new { Data = data, EditUrl = GetEditActionUrl(entityTypeParameter) }.ToDynamic());
        }

        private string GetEditActionUrl(string key)
        {
            foreach (var editAction in editActions)
            {
                var regex = new Regex(editAction.Key);
                if (regex.IsMatch(key))
                {
                    return string.Format(editAction.Value, regex.Match(key).Groups.OfType<Group>().Select(p => p.Value).Skip(1).ToArray());
                }
            }

            return "";
        }

        public ActionResult DeleteMetaLink(int id)
        {
            var linkService = new CmsEntityMetaFieldLinkService();
            var entity = linkService.FindOne(id);
            string type = entity.EntityTypeParameter;

            linkService.Remove(entity);

            return EntityMetaFields(type);
        }

        public ActionResult MoveUp(int id)
        {
            var linkService = new CmsEntityMetaFieldLinkService();
            var entity = linkService.MoveUp(id);
            return EntityMetaFields(entity.EntityTypeParameter);
        }

        public ActionResult MoveDown(int id)
        {
            var linkService = new CmsEntityMetaFieldLinkService();
            var entity = linkService.MoveDown(id);
            return EntityMetaFields(entity.EntityTypeParameter);
        }

        public ActionResult AddValue(int linkId, string value)
        {
            var linkService = new CmsEntityMetaFieldLinkService();
            var metaLink = linkService.FindOne(linkId);
            var providerSettings = metaLink.MetaFieldValues.DigUpFromString<CmsEntityMetaFieldLinkValue>();
            var provider = MetaValuesProviderManager.Provider(providerSettings.ProviderName);
            if (provider != null)
            {
                return Json(provider.AddNewItem(value, providerSettings.Settings));
            }
            return Json(new { error = "Can't add new value." });
        }

        public ActionResult EntityMetaValues(CmsEntityMetaInformation metaInformation, bool isValid = false)
        {
            if (metaInformation.MetaFieldLinks == null)
            {
                return null;
            }
            var model = new List<CmsEntityMetaModel>();
            foreach (var metaLink in metaInformation.MetaFieldLinks)
            {
                if (!metaLink.EntityMetaField.IsSystem)
                {
                    continue;
                }

                var item = new CmsEntityMetaModel()
                {
                    Label = metaLink.DisplayLabel,
                    Type = metaLink.EntityMetaField.MetaFieldType,
                    Name = metaLink.EntityMetaField.MetaFieldName,
                    Value = TryGetValue(metaLink, metaInformation.Metas),
                    IsRequired = metaLink.IsRequired
                };
                List<CmsKeyValueItem> items = new List<CmsKeyValueItem>();
                try
                {
                    var value = metaLink.MetaFieldValues.DigUpFromString<CmsEntityMetaFieldLinkValue>();
                    var provider = MetaValuesProviderManager.Provider(value.ProviderName);
                    if (provider != null)
                    {
                        items = provider.GetDataSource(value.Settings).ToList();
                        if (value.AddPleaseSelect)
                        {
                            items.Insert(0,
                                new CmsKeyValueItem() {Key = "", Value = GetText("Please select", "cms_Metas")});
                        }
                        item.CanAddNew = provider.CanAddItem;
                        item.MetaValuesProviderName = provider.Name;
                    }
                }
                catch
                {
                    items = new List<CmsKeyValueItem>();
                }

                item.EditorName = GetEditorName(metaLink, items);
                var val = item.Value as IEnumerable;
                val = val ?? new [] {item.Value ?? (items.FirstOrDefault(p => p.Selected) ?? new CmsKeyValueItem()).Key};
                item.AdditionalValues =
                    new
                        {
                            DataSource = new MultiSelectList(items, "Key", "Value", val),
                            item.CanAddNew,
                            LinkId = metaLink.Id,
                            Attributes = GetValidationAttriubtes(item)
                        };

                model.Add(item);
            }

            int i = 0;
            foreach (var modelItem in model)
            {
                if (!isValid && modelItem.IsRequired && (modelItem.Value as string) == "")
                {
                    ModelState.AddModelError("Metas[" + i + "].Value", GetText("{0} is required", "cms_Metas", modelItem.Label));
                }
                i++;
            }

            return PartialView("MetaFields/EntityMetaValues", new CmsEntityMetaModelContainer() { Metas = model });
        }

        private static object GetValidationAttriubtes(CmsEntityMetaModel item)
        {
            if (item.IsRequired)
            {
                return new { data_val = "true", data_val_required = GetText("{0} is required", "cms_Metas", item.Label), @class = "required" };
            }

            if (item.Type.IndexOf("int", StringComparison.OrdinalIgnoreCase) > -1 || item.Type.IndexOf("double", StringComparison.OrdinalIgnoreCase) > -1)
            {
                return new { data_val = "true", @class = "number" };
            }
            return null;
        }

        internal static string GetEditorName(CmsEntityMetaFieldLink metaLink, List<CmsKeyValueItem> items)
        {
            if (!string.IsNullOrEmpty(metaLink.EditorName))
            {
                return metaLink.EditorName;
            }

            string result = "Common";

            if (items != null && items.Count > 0)
            {
                result = metaLink.IsAllowMultipleValues ? "MultiSelect" : "SingleSelect";
            }
            else if (typeEditorMappings.ContainsKey(metaLink.EntityMetaField.MetaFieldType))
            {
                result = typeEditorMappings[metaLink.EntityMetaField.MetaFieldType];
            }

            return result;
        }

        private object TryGetValue(CmsEntityMetaFieldLink metaFieldLink, ICollection<CmsEntityMeta> metas)
        {
            var meta = metas.FirstOrDefault(p => p.MetaFieldName == metaFieldLink.EntityMetaField.MetaFieldName);
            if (meta != null)
            {
                return TypeInterpreter.GetValue(metaFieldLink.EntityMetaField.MetaFieldType, meta.EntityMetaValue,
                                                EntitiesConverter.ConvertToType);
            }

            return TypeInterpreter.GetValue(metaFieldLink.EntityMetaField.MetaFieldType, null, EntitiesConverter.ConvertToType);
        }
    }
}